﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;

namespace Fuxi
{
    public partial class FuxiType
    {
        private double GetHitRates(Func<HandData, bool> scene, Func<HandData, bool> hit, int window)
        {
            var hands = Dealer.AllHands.Where(scene).ToList();
            if (hands.Count > window)
            {
                hands = hands.GetRange(0, window);
            }
            if (hands.Count == 0)
            {
                return 0;
            }
            else
            {
                double numHits = hands.Where(hit).Count();
                return numHits / hands.Count;
            }
        }
        bool IsOppCallingStation()
        {
            var hands = Dealer.AllHands.Where(hand => hand.Actions.Where(a => a.PlayerId == "opp" && a.Type == ActionType.Raise).Count() == 0 &&
                                    hand.Actions.Where(a => a.PlayerId == "fuxi" && a.Type == ActionType.Raise).Count() > 0).ToList();
            if (hands.Count() == 0)
            {
                return false;
            }
            if (hands.Count() > 6)
            {
                hands = hands.GetRange(0, 6);
            }
            double totalRaise = 0;
            double totalFold = 0;
            foreach (var hand in hands)
            {
                totalRaise += hand.Actions.Where(a => a.PlayerId == "fuxi" && a.Type == ActionType.Raise).Count();
                totalFold += hand.Actions.Where(a => a.PlayerId == "opp" && a.Type == ActionType.Fold).Count();
            }
            return totalFold < 0.25 * totalRaise;
        }
        StrategyType GetHandStrategy()
        {

            return StrategyType.Jackel;

        }
        int NumFuxiRaised(int round)
        {
            return H.Actions.Where(a => a.PlayerId == "fuxi" && a.Round == round && a.Type == ActionType.Raise).Count();
        }
        int NumOppRaised(int round)
        {
            return H.Actions.Where(a => a.PlayerId == "opp" && a.Round == round && a.Type == ActionType.Raise).Count();
        }
        bool OppNeverRaised
        {
            get
            {
                return H.Actions.Where(a => a.PlayerId == "opp" && a.Type == ActionType.Raise).Count() == 0;
            }
        }
        double OppSbRaiseRate(int round)
        {
                return GetHitRates(h => !h.HavePosition && h.LastRound >= round && 
                              h.Actions.Where(a=>a.PlayerId == "fuxi" && a.Type == ActionType.Raise).Count() == 0,
                              h => h.Actions.Where(a => a.PlayerId == "opp" && a.Round == round && a.Type == ActionType.Raise).Count() > 0, 6);
        }

        public bool ShouldStatRaise
        {
            get
            {
                if (!OppNeverRaised)
                {
                    return false;
                }
                int count = H.Actions.Count;
                double oppFoldRate;
                if (count != 0)
                {
                    oppFoldRate = GetHitRates(h => (h.Actions.Count >= count + 2 &&
                                                  h.Actions.GetRange(0, count).SequenceEqual(H.Actions)),
                                                  h => h.Actions[count].Type == ActionType.Raise &&
                                                  h.Actions[count + 1].Type == ActionType.Fold, 6);
                }
                else
                {
                    oppFoldRate = GetHitRates(h => h.Actions.Count >= 2,
                              h => h.Actions[0].PlayerId == "fuxi" && h.Actions[0].Type == ActionType.Raise &&
                              h.Actions[1].Type == ActionType.Fold, 6);
                }
                double chipsToInvest = 0;
                if (H.HavePosition && H.FirstPreflopPass)
                {
                    chipsToInvest = 1.5;
                }
                else if (F.Round == G.Preflop || F.Round == G.Flop)
                {
                    chipsToInvest = (F.CanCheck ? 1 : 2);
                }
                else if (F.Round == G.Turn || F.Round == G.River)
                {
                    chipsToInvest = (F.CanCheck ? 2 : 4);
                }
                return chipsToInvest < (chipsToInvest + F.Pot) * oppFoldRate;
            }
        }

        double ImpliedPotOdds
        {
            get
            {
                int count = H.Actions.Count;
                var hands = Dealer.AllHands.Where(h => h.LastRound == G.River).ToList();
                if (hands.Count > 5)
                {
                    hands = hands.GetRange(0, 5);
                }
                if (hands.Count == 0)
                {
                    return F.ChipsToCall / (F.ChipsToCall + F.Pot);
                }
                double potOdds = 0;
                foreach (var h in hands)
                {
                    int startRound = (H.HavePosition && H.FirstPreflopPass) ? G.Preflop : F.Round + 1;
                    double newPot = 0, newChipsToCall = 0;
                    for (int i = startRound; i <= G.River; i++)
                    {
                        int numOppRaise = h.Actions.Where(a => a.Round == i && a.PlayerId == "opp" && a.Type == ActionType.Raise).Count();
                        if (numOppRaise > 0)
                        {
                            if (i == G.Preflop || i == G.Flop)
                            {
                                newPot += 2;
                                newChipsToCall += 1;
                            }
                            else if (i == G.Turn || i == G.River)
                            {
                                newPot += 4;
                                newChipsToCall += 2;
                            }
                        }
                    }
                    potOdds += (F.ChipsToCall + newChipsToCall) / (F.ChipsToCall + F.Pot + newPot);
                }
                return potOdds / hands.Count;
            }
        }
    }
}
